package com.mew.chess.core.game.qmcs.service;

import cn.hutool.core.util.RandomUtil;
import com.mew.chess.core.common.handler.GameCommonService;
import com.mew.chess.core.common.handler.MaxBonusService;
import com.mew.chess.core.common.provide.GameFeignService;
import com.mew.chess.core.game.qmcs.game.QmcsGameManager;
import com.mew.chess.core.game.qmcs.game.QmcsTableManager;
import com.mew.chess.core.game.qmcs.game.common.*;
import com.mew.chess.core.game.qmcs.game.message.QmcsCMDMapType;
import com.mew.chess.core.game.qmcs.game.message.QmcsKillResponseMessage;
import com.mew.chess.core.game.qmcs.game.message.request.QmcsHitRequestMessage;
import com.mew.chess.core.game.shbz.game.common.FishTableLog;
import com.mew.common.dc.redis.UserProfileRedisService;
import com.mew.common.entity.config.FishingQmcs;
import com.mew.common.entity.game.WinFree;
import com.mew.common.exception.ResponseCode;
import com.mew.common.rest.LongMessage;
import com.mew.common.rest.game.BetAfterRequest;
import com.zebra.common.concurrent.ZebraExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.stream.Collectors;

@Slf4j
@Service
public class QmcsService {

    @Autowired
    private GameFeignService feignService;
    @Autowired
    private UserProfileRedisService userProfileRedisService;
    @Autowired
    private MaxBonusService maxBonusService;
    @Autowired
    private GameCommonService gameCommonService;

    public LongMessage bet(long userId, int roomId, QmcsHitRequestMessage requestMessage) {
        LongMessage longMessage = new LongMessage();

        QmcsTableManager table = QmcsGameManager.getInstance().getController(roomId).getTableByUserId(userId);

        int fishId = requestMessage.getQmcsId();
        int betId = requestMessage.getBetId();

        QmcsUserBO qmcsUserBO = table.getOnlineUserMap().get(userId);

        QmcsBO qmcsBO = table.getQmcsMap().get(fishId);
        if (qmcsBO !=null && qmcsBO.getRemainStep()* QmcsConstantValue.STEP_TIME< qmcsBO.getRuleStep()){
            FishTableLog fishTableLog = table.getFishTablelog(qmcsBO.getFishType());
            //活着
            int fishType = qmcsBO.getFishType();
            FishingQmcs fishingQmcs = QmcsGameManager.getInstance().getQmcsMap().get(fishType);
            if (qmcsUserBO.getFreeTimes()>0){
                betId = qmcsUserBO.getFreeBetId();
            }
            int bet = QmcsGameManager.getInstance().getController(roomId).getBets()[betId-1];

            long payment = 0;
            int score = 0;

            if (qmcsUserBO.getGoldNumber()<bet){
                return longMessage.buildByResponseCode(ResponseCode.GoldNo);
            }

            HashMap<Integer, QmcsLog> map = qmcsUserBO.getFishLogMap().get(bet);
            if (null==map){
                map = new HashMap<>();
                qmcsUserBO.getFishLogMap().put(bet,map);
            }
            QmcsLog qmcsLog = map.get(fishType);
            if (null== qmcsLog){
                qmcsLog = new QmcsLog();
                map.put(bet, qmcsLog);
            }

            qmcsBO.setStartTime(System.currentTimeMillis() - requestMessage.getRemainStep() * QmcsConstantValue.STEP_TIME);

            QmcsKillResponseMessage message = new QmcsKillResponseMessage();
            fishTableLog.hit++;
            table.playTimes++;
            if (RandomUtil.randomInt(1000)< QmcsConstantValue.DODGE){
                qmcsLog.dodge++;
                table.dodgeTimes++;
                addGold(qmcsUserBO, bet, 0,betId,0,message);
            } else if (fishingQmcs.kill()){
                qmcsBO = table.getQmcsMap().remove(fishId);
                fishTableLog.kill++;
                if (null== qmcsBO){
                    longMessage.setL(qmcsUserBO.getGoldNumber());
                    return longMessage;
                }

                int bouns = fishingQmcs.bouns();

                qmcsLog.kill++;
                //击杀
                score = bouns==0?fishingQmcs.getScore():0;
                payment += score*bet;

                message = QmcsKillResponseMessage.builder()
                        .fishType(fishType)
                        .seatNo(requestMessage.getSeatId())
                        .fishId(fishId)
                        .betId(betId)
                        .bulletId(requestMessage.getBulletId())
                        .winNumber(payment)
                        .maxMultiple(score)
                        .freeBetId(-1)
                        .slots(new ArrayList<>())
                        .build();

                //发消息

                long goldNumber = qmcsUserBO.getGoldNumber() -(qmcsUserBO.getFreeTimes()>0?0:bet) + payment;
                message.setGoldNumber(goldNumber);

                addGold(qmcsUserBO, bet, payment,betId,bouns,message);

                QmcsTableUtil.sendMsgByTable(table,message, QmcsCMDMapType.KillMessage.code(), 0);
                maxBonusService.addMaxBonus(userId,qmcsUserBO.getGameId(),payment,score);
                fishTableLog.bet += bet;
                fishTableLog.payment += payment;
            }else {
                //沒殺死  沒免傷  直接扣押注
                addGold(qmcsUserBO, bet, 0,betId,0,message);
            }

            qmcsLog.hit++;

            if (qmcsUserBO.getFreeTimes()>0){
                qmcsUserBO.setFreeTimes(qmcsUserBO.getFreeTimes()-1);
                if (qmcsUserBO.getFreeTimes()==0){
                    qmcsUserBO.setFreeBetId(-1);
                }
            }

            upWinFree(qmcsUserBO);
            //奖励炮弹

        }
        longMessage.setL(qmcsUserBO.getGoldNumber());
        return longMessage;

    }

    private void addGold(QmcsUserBO qmcsUserBO, long bet, long payment, int betId, int bouns, QmcsKillResponseMessage message){

        message.setBounsType(bouns);
        if (bouns==1){
            //多一次减这次的
            qmcsUserBO.setFreeTimes(qmcsUserBO.getFreeTimes()+61);
            qmcsUserBO.setFreeBetId(betId);

        }else if (bouns==2){
            ArrayList<QmcsSlots> list = new ArrayList<>();
            for (int i = 0; i < 5; i++) {
                QmcsSlots qmcsSlots = new QmcsSlots();
                qmcsSlots.init(message.getFishType()==19?1:0);
                qmcsSlots.setGold(qmcsSlots.getMult()*bet);
                list.add(qmcsSlots);
            }
            message.setSlots(list);

        }
        message.setFreeTimes(qmcsUserBO.getFreeTimes());
        message.setFreeBetId(qmcsUserBO.getFreeBetId());

        long goldNumber = 0;
        qmcsUserBO.setPayment(qmcsUserBO.getPayment()+payment);
        qmcsUserBO.setBet(qmcsUserBO.getBet()+(qmcsUserBO.getFreeTimes()>0?0:bet));

        if (bouns==2){
            goldNumber+=message.getSlots().stream().mapToLong(QmcsSlots::getGold).sum();
            qmcsUserBO.setPayment(qmcsUserBO.getPayment()+goldNumber);
        }

        qmcsUserBO.updateGoldNumber(payment+goldNumber-(qmcsUserBO.getFreeTimes()>0?0:bet));

    }

    public void payment(int roomId,int tableId){
        QmcsTableManager table = QmcsGameManager.getInstance().getController(roomId).getTable(tableId);
        ArrayList<QmcsUserBO> qmcsUserBOS = new ArrayList<>(table.getOnlineUserMap().values());

        for (QmcsUserBO userBO : qmcsUserBOS) {
            ZebraExecutor executor = QmcsGameManager.getInstance().getDisruptorByUserId(userBO.getUserId());
            executor.execute(()->{
                doPayment(userBO);
            });
            table.lostConnection(userBO.getUserId());
        }

        gameCommonService.checkTMSOnline(table.getOnlineUserMap().values().stream().map(QmcsUserBO::getGameSession).collect(Collectors.toList()), QmcsGameManager.getInstance().getGameId(), roomId);

    }



    public void doPayment(QmcsUserBO userBO){

        if (userBO.getBet()==0 && userBO.getPayment()==0){
            return;
        }

        BetAfterRequest request = BetAfterRequest.builder()
                .uid(userBO.getUserId())
                .relateInoutId(userBO.getInoutId())
                .gameId(userBO.getGameId())
                .roomId(userBO.getRoomId())
                .bet(userBO.getBet())
                .payment(userBO.getPayment())
                .rollerId(0)
                .betTimes((userBO.getBet()==0 || userBO.getPayment() < 1) ? 0 : (int) (userBO.getPayment() / userBO.getBet()))
                .iconResult("")
                .betArray("")
                .roomRecord(1)
                .paymentArray("")
                .build();

        userBO.setBet(0);
        userBO.setPayment(0);

        ArrayList<BetAfterRequest> list = new ArrayList<BetAfterRequest>() {{
            add(request);
        }};
        feignService.chessBetAfter(list);

    }

    public void upWinFree(QmcsUserBO qmcsUserBO){
        WinFree winFree = userProfileRedisService.getRedisWinfree(qmcsUserBO.getUserId(), qmcsUserBO.getRoomId());
        if (winFree.getFreeNumber()!=qmcsUserBO.getFreeTimes()){
            winFree.setFreeNumber(qmcsUserBO.getFreeTimes());
            winFree.setFreeType(qmcsUserBO.getFreeBetId());
            userProfileRedisService.updateRedisWinfree(winFree);
        }
    }

    public void tableLog(QmcsTableManager table,boolean r) {
        long logTime = table.getLogTime();
        long nowTime = System.currentTimeMillis();
        if (r||nowTime-logTime>300000){
            table.setLogTime(nowTime);
            log.info("qmcs,room{},table{},游戏次数,{},免伤次数,{},比例,{}", table.getRoomId(), table.getTableId(), table.playTimes, table.dodgeTimes, table.playTimes>0?((double) table.dodgeTimes)/ table.playTimes:0);
            table.playTimes = 0;
            table.dodgeTimes = 0;
            HashMap<Integer, FishTableLog> logMap = table.getLogMap();
            StringBuilder builder = new StringBuilder();
            logMap.forEach((k,v)->{
                double jsl = v.hit > 0 ? ((double) v.kill) / v.hit : 0;
                builder.append("room"+ table.getRoomId() +",鬼类型："+k+",攻击："+v.hit+",杀死："+v.kill + ",击杀率："+jsl +",押注："+v.bet+",赔付："+ v.payment+"\n");
            });
            log.info("qmcs,room"+ table.getRoomId()+",table"+ table.getTableId()+",\n"+builder.toString());
            logMap.clear();
        }
    }
}
